package cn.sylinx.hbatis.db.common;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.sylinx.hbatis.db.dialect.DbType;
import cn.sylinx.hbatis.db.dialect.Dialect;
import cn.sylinx.hbatis.db.dialect.DialectFatory;
import cn.sylinx.hbatis.db.mapper.ModelBuilder;
import cn.sylinx.hbatis.db.mapper.QueryMapper;
import cn.sylinx.hbatis.ds.JdbcBlock;
import cn.sylinx.hbatis.ds.JdbcResource;
import cn.sylinx.hbatis.ds.JdbcResourceManager;
import cn.sylinx.hbatis.ds.ResourceHelper;
import cn.sylinx.hbatis.exception.ErrorCodeRecordable;
import cn.sylinx.hbatis.exception.HbatisException;
import cn.sylinx.hbatis.exception.NestedTransactionException;
import cn.sylinx.hbatis.kit.DbKit;
import cn.sylinx.hbatis.kit.Ret;
import cn.sylinx.hbatis.kit.Tuple;
import cn.sylinx.hbatis.log.GLog;
import cn.sylinx.hbatis.plugin.datasource.JdbcResourcePlugin;
import cn.sylinx.hbatis.plugin.model.ModelFabric;
import cn.sylinx.hbatis.plugin.transaction.TransactionIsolationWrapper;

/**
 * 数据库操作类
 * 
 * @author han
 *
 */
class DbPro {

	/**
	 * 默认批量提交数量
	 */
	public static final int DEFAULT_BATCH_SIZE = 500;

	/**
	 * 数据源
	 */
	private final JdbcResource jdbcResource;

	/**
	 * 数据源名称
	 */
	private final String dataSourceName;

	/**
	 * 方言
	 */
	private final Dialect dialect;

	/**
	 * 构造器
	 * 
	 * @param jdbcResourceName 数据源名称
	 */
	DbPro(String jdbcResourceName) {

		this.jdbcResource = JdbcResourceManager.get().get(jdbcResourceName);
		if (this.jdbcResource == null) {
			throw new HbatisException("jdbc resource not found by jdbcResourceName: " + jdbcResourceName);
		}
		this.dataSourceName = jdbcResource.getDataSourceName();
		this.dialect = DialectFatory.get().createDialect(jdbcResource.getDbType());
	}

	/**
	 * 获取数据源名称
	 * 
	 * @return 据源名称
	 */
	public String getDataSourceName() {
		return dataSourceName;
	}

	/**
	 * 获取方言
	 * 
	 * @return
	 */
	public Dialect getDialect() {
		return dialect;
	}

	/**
	 * 自定义操作
	 * 
	 * @param callable
	 * @return
	 */
	public <T> T call(Callable<T> callable) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<T>() {
			@Override
			public T applyBlock(Connection conn) throws SQLException {
				return callable.call(conn);
			}
		});
	}

	/**
	 * 使用特定的DdPro
	 * 
	 * @param jdbcResourceName 数据源名称
	 * @return DbPro对象
	 */
	public static DbPro use(String jdbcResourceName) {
		return new DbPro(jdbcResourceName);
	}

	/**
	 * 使用默认的DdPro
	 * 
	 * @return DbPro对象
	 */
	public static DbPro use() {
		return new DbPro(JdbcResourcePlugin.DEFAULT_JDBC_RESOURCE_NAME);
	}

	/**
	 * 默认500提交
	 * 
	 * @param sql sql语句列表
	 * @return 影响行数
	 */
	public int[] batch(final List<String> sql) {
		return batch(sql, DEFAULT_BATCH_SIZE);
	}

	/**
	 * 默认500提交，预编译
	 * 
	 * @param sql    sql语句
	 * @param params 参数数组
	 * @return 影响行数
	 */
	public int[] batch(final String sql, final Object[][] params) {
		return batch(sql, params, DEFAULT_BATCH_SIZE);
	}

	/**
	 * 批量执行
	 * 
	 * @param sql       sql语句
	 * @param params    参数
	 * @param batchSize 批量提交数
	 * @return 影响行数
	 */
	public int[] batch(final String sql, final Object[][] params, final int batchSize) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<int[]>() {

			private int[] batchInner(Connection conn, final String sql, final Object[][] params, final int batchSize)
					throws SQLException {

				if (params == null || params.length == 0)
					throw new IllegalArgumentException("The paras array length must more than 0.");
				if (batchSize < 1)
					throw new IllegalArgumentException("The batchSize must more than 0.");

				int counter = 0;
				int pointer = 0;
				int[] result = new int[params.length];
				PreparedStatement pst = conn.prepareStatement(sql);
				for (int i = 0; i < params.length; i++) {

					dialect.setParameters(pst, params[i]);

					pst.addBatch();
					if (++counter >= batchSize) {
						counter = 0;
						int[] r = pst.executeBatch();
						conn.commit();
						for (int k = 0; k < r.length; k++)
							result[pointer++] = r[k];
					}
				}
				int[] r = pst.executeBatch();
				conn.commit();
				for (int k = 0; k < r.length; k++)
					result[pointer++] = r[k];
				DbKit.closeQuietly(pst);
				return result;
			}

			@Override
			public int[] applyBlock(Connection conn) throws SQLException {

				Boolean autoCommit = null;
				try {
					autoCommit = conn.getAutoCommit();
					conn.setAutoCommit(false);
					return batchInner(conn, sql, params, batchSize);

				} catch (Exception e) {
					GLog.error("batch error:", e);
					conn.rollback();
					return null;

				} finally {
					if (autoCommit != null) {
						conn.setAutoCommit(autoCommit);
					}
				}
			}

		});
	}

	/**
	 * 批量执行
	 * 
	 * @param sqlList   sql语句列表
	 * @param batchSize 批量提交数量
	 * @return 影响行数
	 */
	public int[] batch(final List<String> sqlList, final int batchSize) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<int[]>() {

			private int[] batchInner(Connection conn, final List<String> sqlList, final int batchSize)
					throws SQLException {

				if (sqlList == null || sqlList.size() == 0)
					throw new IllegalArgumentException("The sqlList length must more than 0.");
				if (batchSize < 1)
					throw new IllegalArgumentException("The batchSize must more than 0.");
				int counter = 0;
				int pointer = 0;
				int size = sqlList.size();
				int[] result = new int[size];
				Statement st = conn.createStatement();
				for (int i = 0; i < size; i++) {
					st.addBatch(sqlList.get(i));
					if (++counter >= batchSize) {
						counter = 0;
						int[] r = st.executeBatch();
						conn.commit();
						for (int k = 0; k < r.length; k++)
							result[pointer++] = r[k];
					}
				}
				int[] r = st.executeBatch();
				conn.commit();
				for (int k = 0; k < r.length; k++)
					result[pointer++] = r[k];
				DbKit.closeQuietly(st);
				return result;
			}

			@Override
			public int[] applyBlock(Connection conn) throws SQLException {

				Boolean autoCommit = null;
				try {
					autoCommit = conn.getAutoCommit();
					conn.setAutoCommit(false);
					return batchInner(conn, sqlList, batchSize);

				} catch (Exception e) {
					GLog.error("batch error:", e);
					conn.rollback();
					return null;

				} finally {
					if (autoCommit != null) {
						conn.setAutoCommit(autoCommit);
					}

				}

			}

		});
	}

	/**
	 * 执行事务
	 * 
	 * @param transaction 事务对象
	 * @return 是否执行成功
	 */
	public boolean transaction(final ITransaction transaction) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Boolean>() {

			@Override
			public Boolean applyBlock(Connection conn) throws SQLException {

				Connection transCon = jdbcResource.getTransactionConnection();

				if (transCon != null) { // Nested transaction support
					Ret result = transaction.run();
					if (result.isSuccess())
						return true;

					throw new NestedTransactionException(
							"Notice the outer transaction that the nested transaction return false");
					// important:can not return false
				}

				Boolean autoCommit = null;
				try {

					autoCommit = conn.getAutoCommit();
					int transactionIsolation = (transaction.transactionIsolation() == null
							? TransactionIsolationWrapper.ME.getTransactionIsolation()
							: transaction.transactionIsolation().intValue());
					conn.setTransactionIsolation(transactionIsolation);
					conn.setAutoCommit(false);
					jdbcResource.setTransactionConnection(conn);

					Ret result = transaction.run();
					if (result.isSuccess()) {
						conn.commit();

					} else {
						conn.rollback();
					}

					return result.isSuccess();

				} catch (Throwable t) {

					GLog.error("transaction error :", t);
					conn.rollback();

				} finally {

					conn.setAutoCommit(autoCommit);
					jdbcResource.removeTransactionConnection();
				}

				return false;

			}
		});
	}

	/**
	 * 带有返回信息的事务处理
	 * 
	 * @param transaction
	 * @return
	 */
	public Ret transactionWithReturn(final ITransaction transaction) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Ret>() {

			@Override
			public Ret applyBlock(Connection conn) throws SQLException {

				Connection transCon = jdbcResource.getTransactionConnection();

				if (transCon != null) { // Nested transaction support
					Ret result = transaction.run();
					if (result.isSuccess())
						return Ret.success();

					throw new NestedTransactionException(
							"Notice the outer transaction that the nested transaction return false");
					// important:can not return false
				}

				Boolean autoCommit = null;
				try {

					autoCommit = conn.getAutoCommit();
					int transactionIsolation = (transaction.transactionIsolation() == null
							? TransactionIsolationWrapper.ME.getTransactionIsolation()
							: transaction.transactionIsolation().intValue());
					conn.setTransactionIsolation(transactionIsolation);
					conn.setAutoCommit(false);
					jdbcResource.setTransactionConnection(conn);

					Ret result = transaction.run();
					if (result.isSuccess()) {
						conn.commit();

					} else {
						conn.rollback();
					}

					return result;

				} catch (Throwable t) {

					GLog.error("transaction error :", t);
					conn.rollback();
					int code = 500;
					if (ErrorCodeRecordable.class.isAssignableFrom(t.getClass())) {
						code = ((ErrorCodeRecordable) t).getCode();
					}
					return Ret.error(code, t.getMessage());

				} finally {

					conn.setAutoCommit(autoCommit);
					jdbcResource.removeTransactionConnection();
				}

			}
		});
	}

	/**
	 * 删除
	 * 
	 * @param t
	 * @return
	 */
	public <T> int delete(T t) {

		if (t == null) {
			throw new HbatisException("模型为空");
		}

		Tuple tuple = null;

		try {
			tuple = getDialect().getSqlBuilder().buildDeleteSQL(t);
		} catch (Exception e) {
			GLog.error("ModelBuilder.buildDeleteSQL(t, mapper) error: ", e);
		}

		if (tuple == null) {
			return 0;
		}

		String updateSql = (String) tuple.get(0);
		Object[] params = (Object[]) tuple.get(1);

		return update(updateSql, params);
	}

	/**
	 * 
	 * @param t
	 * @return
	 */
	public <T> Serializable save(T t) {

		if (t == null) {
			throw new HbatisException("模型为空");
		}

		Tuple tuple = null;

		try {
			tuple = getDialect().getSqlBuilder().buildInsertSQL(t);
		} catch (Exception e) {
			GLog.error("ModelBuilder.buildInsertSQL(t, mapper) error: ", e);
		}

		if (tuple == null) {
			return null;
		}

		String updateSql = (String) tuple.get(0);
		Object[] params = (Object[]) tuple.get(1);

		return save(updateSql, params);
	}

	/**
	 * 对象更新
	 * 
	 * @param t      T对象
	 * @param mapper 更新mapper
	 * @return 影响行数
	 */
	public <T> int update(T t) {

		if (t == null) {
			throw new HbatisException("更新对象为空");
		}

		Tuple tuple = null;

		try {
			tuple = getDialect().getSqlBuilder().buildUpdateSQL(t);
		} catch (Exception e) {
			GLog.error("ModelBuilder.buildUpdateSQL(t, mapper) error: ", e);
			throw new RuntimeException(e);
		}

		if (tuple == null) {
			return 0;
		}

		String updateSql = (String) tuple.get(0);
		Object[] params = (Object[]) tuple.get(1);

		return update(updateSql, params);
	}

	/**
	 * Executes the SQL statement in this PreparedStatement object, which may be any
	 * kind of SQL statement. Some prepared statements return multiple results; the
	 * execute method handles these complex statements as well as the simpler form
	 * of statements handled by the methods executeQuery and executeUpdate.
	 * 
	 * The execute method returns a boolean to indicate the form of the first
	 * result. You must call either the method getResultSet or getUpdateCount to
	 * retrieve the result; you must call getMoreResults to move to any subsequent
	 * result(s).
	 * 
	 * @param exeSql
	 * @param params
	 * @return true if the first result is a ResultSet object; false if the first
	 *         result is an update count or there is no result
	 */
	public boolean execute(final String exeSql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Boolean>() {

			@Override
			public Boolean applyBlock(Connection conn) throws SQLException {

				PreparedStatement pst = conn.prepareStatement(exeSql);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				boolean bl = pst.execute();
				DbKit.closeQuietly(pst);
				return bl;
			}
		});

	}

	public boolean executeLargeUpdate(final List<String> exeSqlList) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Boolean>() {

			@Override
			public Boolean applyBlock(Connection conn) {

				try {

					Statement st = conn.createStatement();
					for (String sql : exeSqlList) {
						st.addBatch(sql);
					}
					int[] rst = st.executeBatch();
					GLog.info("executeLargeUpdate rst:{}", rst);
					DbKit.closeQuietly(st);

				} catch (Exception e) {
					GLog.error("executeLargeUpdate error ", e);
					return false;
				}

				return true;
			}
		});

	}

	/**
	 * 更新操作，包括删除
	 * 
	 * @param updateSql 更新sql
	 * @param params    参数
	 * @return 影响行数
	 */
	public int update(final String updateSql, final Object... params) {

		return call((conn) -> {

			PreparedStatement pst = conn.prepareStatement(updateSql);

			if (params != null) {
				dialect.setParameters(pst, params);
			}

			int result = pst.executeUpdate();
			if (result < 1) {
				GLog.info("0 rows updated, sql:{}, params:{}", updateSql, params);
			}

			DbKit.closeQuietly(pst);

			return result;
		});
	}

	/**
	 * 保存操作
	 * 
	 * @param insertSql 插入sql
	 * @param params    参数
	 * @return 主键
	 */
	public Serializable save(final String insertSql, final Object... params) {

		if (DbType.CLICKHOUSE == dialect.getDbType()) {
			int count = update(insertSql, params);
			GLog.debug("clickhouse add count: {}", count);
			// clickhouse 无需返回主键
			return null;
		}

		return updateWithReturnPk(insertSql, params);
	}

	/**
	 * 更新返回主键
	 * 
	 * @param updateSql
	 * @param params
	 * @return
	 */
	public Serializable updateWithReturnPk(final String updateSql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Serializable>() {

			@Override
			public Serializable applyBlock(Connection conn) throws SQLException {

				PreparedStatement pst = conn.prepareStatement(updateSql, PreparedStatement.RETURN_GENERATED_KEYS);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				int result = pst.executeUpdate();
				if (result < 1) {
					GLog.error("update error, sql:" + updateSql);
				}

				ResultSet rs = pst.getGeneratedKeys();
				Object pk = rs.next() ? rs.getObject(1) : null;

				DbKit.closeQuietly(rs, pst);

				return (Serializable) pk;
			}
		});

	}

	/**
	 * 获取一条记录
	 * 
	 * @param sql    sql语句
	 * @param params 参数
	 * @return Map记录对象
	 */
	public Map<String, Object> queryFirstMap(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Map<String, Object>>() {

			@Override
			public Map<String, Object> applyBlock(Connection conn) throws SQLException {

				PreparedStatement pst = conn.prepareStatement(sql);
				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				Map<String, Object> result = new HashMap<String, Object>();

				if (rs.next()) {

					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						result.put(rsmetas.getColumnLabel(i).toUpperCase(), rs.getObject(i));
					}
				}

				DbKit.closeQuietly(rs, pst);

				return result;
			}
		});

	}

	/**
	 * 获取第一行数据
	 * 
	 * @param sql    sql语句
	 * @param params 参数
	 * @return Object[] 记录
	 */
	public Object[] queryFirst(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Object[]>() {

			@Override
			public Object[] applyBlock(Connection conn) throws SQLException {

				PreparedStatement pst = conn.prepareStatement(sql);
				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				Object[] result = null;

				if (rs.next()) {

					result = new Object[columnCount];
					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						result[i - 1] = rs.getObject(i);
					}
				}

				DbKit.closeQuietly(rs, pst);

				return result;
			}
		});

	}

	/**
	 * 获取第一条记录
	 * 
	 * @param sql    sql语句
	 * @param params 参数
	 * @return Record记录对象
	 */
	public Record queryFirstRecord(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<Record>() {

			@Override
			public Record applyBlock(Connection conn) throws SQLException {

				PreparedStatement pst = conn.prepareStatement(sql);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				Record tmp = null;
				if (rs.next()) {

					tmp = new Record();
					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						tmp.put(rsmetas.getColumnLabel(i), i, rs.getObject(i));
					}
				}

				DbKit.closeQuietly(rs, pst);

				return tmp;
			}
		});

	}

	/**
	 * 查询数据
	 * 
	 * @param sql    sql语句
	 * @param params 参数列表
	 * @return Record列表记录
	 */
	public List<Record> queryRecords(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<List<Record>>() {

			@Override
			public List<Record> applyBlock(Connection conn) throws SQLException {

				List<Record> result = new ArrayList<Record>();

				PreparedStatement pst = conn.prepareStatement(sql);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				Record tmp = null;
				while (rs.next()) {

					tmp = new Record();
					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						tmp.put(rsmetas.getColumnLabel(i), i, rs.getObject(i));
					}

					result.add(tmp);
				}

				DbKit.closeQuietly(rs, pst);

				return result;
			}
		});

	}

	/**
	 * 查询数据
	 * 
	 * @param sql    sql语句
	 * @param params 参数
	 * @return 数据记录列表
	 */
	public List<Map<String, Object>> queryMap(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<List<Map<String, Object>>>() {

			@Override
			public List<Map<String, Object>> applyBlock(Connection conn) throws SQLException {

				List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();

				PreparedStatement pst = conn.prepareStatement(sql);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				Map<String, Object> tmp = null;
				while (rs.next()) {

					tmp = new HashMap<String, Object>();
					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						tmp.put(rsmetas.getColumnLabel(i).toUpperCase(), rs.getObject(i));
					}

					result.add(tmp);
				}

				DbKit.closeQuietly(rs, pst);

				return result;
			}
		});

	}

	/**
	 * 查询数据，返回对象列表
	 * 
	 * @param sql    sql语句
	 * @param params 参数
	 * @return 数据列表
	 */
	public List<Object[]> query(final String sql, final Object... params) {

		return ResourceHelper.using(jdbcResource, new JdbcBlock<List<Object[]>>() {

			@Override
			public List<Object[]> applyBlock(Connection conn) throws SQLException {

				List<Object[]> result = new ArrayList<Object[]>();

				PreparedStatement pst = conn.prepareStatement(sql);

				if (params != null) {
					dialect.setParameters(pst, params);
				}

				ResultSet rs = pst.executeQuery();
				ResultSetMetaData rsmetas = rs.getMetaData();
				int columnCount = rsmetas.getColumnCount();

				while (rs.next()) {

					Object[] row = new Object[columnCount];
					for (int i = 1, len = columnCount + 1; i < len; ++i) {
						row[i - 1] = rs.getObject(i);
					}

					result.add(row);
				}

				DbKit.closeQuietly(rs, pst);

				return result;
			}
		});

	}

	/**
	 * 获取第一条记录
	 * 
	 * @param sql    sql语句
	 * @param mapper 查询mapper
	 * @param params 参数
	 * @return T对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T queryFirst(final String sql, final QueryMapper<T> mapper, final Object... params) {

		if (mapper == null) {
			return (T) queryFirst(sql, params);
		}

		return call((conn) -> {

			PreparedStatement pst = conn.prepareStatement(sql);
			if (params != null) {
				dialect.setParameters(pst, params);
			}

			ResultSet rs = pst.executeQuery();
			T result = null;
			try {
				result = buildFirstQueryModel(rs, mapper);
			} catch (InstantiationException e) {
				GLog.error("buildFirstQueryModel InstantiationException occur:", e);
			} catch (IllegalAccessException e) {
				GLog.error("buildFirstQueryModel IllegalAccessException occur:", e);
			}

			DbKit.closeQuietly(rs, pst);
			return result;
		});
	}

	/**
	 * 获取第一条记录
	 * 
	 * @param rs     ResultSet
	 * @param mapper QueryMapper
	 * @return T
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws Exception
	 */
	public <T> T buildFirstQueryModel(ResultSet rs, QueryMapper<T> mapper)
			throws SQLException, InstantiationException, IllegalAccessException {

		if (mapper == null) {
			return null;
		}

		T result = null;

		ResultSetMetaData rsmd = rs.getMetaData();
		int columnCount = rsmd.getColumnCount();
		String[] labelNames = new String[columnCount + 1];
		int[] types = new int[columnCount + 1];
		ModelBuilder.buildColumnNamesAndTypes(rsmd, labelNames, types);

		// 字段映射关系
		Map<String, String> maps = mapper.getJdbcToJavaMapper();
		// 对象类
		// String className = mapper.getValueObjectClass();
		Class<T> clz = mapper.getValueObjectClass();
		if (clz == null) {
			return null;
		}

		final ModelFabric mf = ModelBuilder.getModelFabric(clz.getName());
		boolean ismapsEmpty = maps == null || maps.isEmpty();
		boolean ismappingEmpty = mf.isMappingEmpty();

		// 如果XML映射关系为空并且对应的Class的注解映射为空
		if (ismapsEmpty && ismappingEmpty) {

			if (rs.next()) {

				result = getDialect().getResult(rs, 1, clz);
			}

		} else {

			if (ismapsEmpty) {
				// 如果XML映射关系为空，则取注解映射关系
				maps = mf.getJdbcMapping();
			}

			Map<String, Field> fieldMap = mf.getFieldMap();

			if (rs.next()) {

				T instance = clz.newInstance();

				for (int i = 1; i <= columnCount; i++) {

					Field f = fieldMap.get(maps.get(labelNames[i]));

					if (f != null) {

						Class<?> tp = f.getType();
						Object tmp1 = getDialect().getResult(rs, i, tp);

						if (tmp1 != null) {
							f.setAccessible(true);
							f.set(instance, tmp1);
						}
					}
				}
				result = instance;
			}
		}

		return result;
	}

	public <T> List<T> queryObject(final String sql, final Class<T> clazz, final Object... params) {

		return call((conn) -> {

			PreparedStatement pst = conn.prepareStatement(sql);
			if (params != null) {
				dialect.setParameters(pst, params);
			}
			ResultSet rs = pst.executeQuery();

			try {
				return buildQueryObject(rs, clazz);
			} finally {
				DbKit.closeQuietly(rs, pst);
			}

		});
	}

	public <T> T queryFirstObject(final String sql, final Class<T> clazz, final Object... params) {

		return call((conn) -> {

			PreparedStatement pst = conn.prepareStatement(sql);
			if (params != null) {
				dialect.setParameters(pst, params);
			}
			ResultSet rs = pst.executeQuery();
			try {
				return buildFirstQueryObject(rs, clazz);
			} finally {
				DbKit.closeQuietly(rs, pst);
			}
		});

	}

	/**
	 * 查询单个列
	 * 
	 * @param rs
	 * @param clazz
	 * @return
	 * @throws SQLException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public <T> List<T> buildQueryObject(ResultSet rs, Class<T> clazz) throws SQLException {
		List<T> result = new ArrayList<T>();
		while (rs.next()) {
			result.add(getDialect().getResult(rs, 1, clazz));
		}
		return result;
	}

	/**
	 * 查询单个列
	 * 
	 * @param rs
	 * @param clazz
	 * @return
	 * @throws SQLException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public <T> T buildFirstQueryObject(ResultSet rs, Class<T> clazz) throws SQLException {

		if (rs.next()) {
			return getDialect().getResult(rs, 1, clazz);
		}

		return null;
	}

	/**
	 * 查询数据
	 * 
	 * @param sql    sql语句
	 * @param mapper 查询mapper
	 * @param params 参数
	 * @return T列表对象
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> query(final String sql, final QueryMapper<T> mapper, final Object... params) {

		if (mapper == null) {
			return (List<T>) query(sql, params);
		}

		return call((conn) -> {

			PreparedStatement pst = conn.prepareStatement(sql);
			if (params != null) {
				dialect.setParameters(pst, params);
			}
			ResultSet rs = pst.executeQuery();
			List<T> result = null;
			try {
				result = buildQueryModel(rs, mapper);
			} catch (InstantiationException e) {
				GLog.error("buildQueryModel InstantiationException occur ", e);
			} catch (IllegalAccessException e) {
				GLog.error("buildQueryModel IllegalAccessException occur ", e);
			}

			DbKit.closeQuietly(rs, pst);
			return result;
		});

	}

	/**
	 * 获取查询结果
	 * 
	 * @param rs     ResultSet
	 * @param mapper QueryMapper
	 * @return List
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws Exception
	 */
	public <T> List<T> buildQueryModel(ResultSet rs, QueryMapper<T> mapper)
			throws SQLException, InstantiationException, IllegalAccessException {

		List<T> result = new ArrayList<T>();
		if (mapper == null) {
			return result;
		}

		ResultSetMetaData rsmd = rs.getMetaData();
		int columnCount = rsmd.getColumnCount();
		String[] labelNames = new String[columnCount + 1];
		int[] types = new int[columnCount + 1];
		ModelBuilder.buildColumnNamesAndTypes(rsmd, labelNames, types);

		// 字段映射关系
		Map<String, String> maps = mapper.getJdbcToJavaMapper();
		// 对象类
		Class<T> clz = mapper.getValueObjectClass();
		if (clz == null) {
			return null;
		}

		ModelFabric mf = ModelBuilder.getModelFabric(clz.getName());
		// 类对应所有字段
		Map<String, Field> fieldMap = mf.getFieldMap();

		boolean ismapsEmpty = maps == null || maps.isEmpty();
		boolean ismappingEmpty = mf.isMappingEmpty();

		// 如果XML映射关系为空并且对应的Class的注解映射为空
		if (ismapsEmpty && ismappingEmpty) {

			while (rs.next()) {
				T tmp1 = getDialect().getResult(rs, 1, clz);
				result.add(tmp1);
			}

		} else {

			if (ismapsEmpty) {
				// 如果XML映射关系为空，则取注解映射关系
				maps = mf.getJdbcMapping();
			}

			while (rs.next()) {

				T instance = clz.newInstance();

				for (int i = 1; i <= columnCount; i++) {

					Field f = fieldMap.get(maps.get(labelNames[i]));

					if (f != null) {

						Class<?> tp = f.getType();
						Object tmp1 = getDialect().getResult(rs, i, tp);

						if (tmp1 != null) {
							f.setAccessible(true);
							f.set(instance, tmp1);
						}
					}
				}
				result.add(instance);
			}

		}

		return result;
	}

	/**
	 * 是否存在表
	 * 
	 * @param schema
	 * @param table
	 * @return
	 */
	public boolean existTable(final String schema, final String table) {

		return call((conn) -> {

			boolean result = false;
			DatabaseMetaData dm = conn.getMetaData();
			ResultSet rs = dm.getTables(null, schema, table, new String[] { "TABLE" });
			result = rs.next();
			DbKit.closeQuietly(rs);
			return result;
		});
	}

	public boolean existTableColumn(final String schema, final String table, final String column) {

		return call((conn) -> {

			boolean result = false;
			DatabaseMetaData dm = conn.getMetaData();
			ResultSet rs = dm.getColumns(null, schema, table, column);
			result = rs.next();
			DbKit.closeQuietly(rs);
			return result;
		});
	}

}
